﻿using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

namespace Fetches.Fetch.Utils
{
    /// <summary>
    /// 对组件管理做了下简单的封装
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ComponentBox<T> where T : IDisposable
    {
        private readonly ConcurrentDictionary<long, T> _componentCache;

        private readonly Action<T, long> _initializeAction;
        private readonly Func<string, T> _getInstanceService;
       

        public ComponentBox(Func<string, T> getInstanceService, Action<T, long> initializeAction)
        {
            _componentCache = new ConcurrentDictionary<long, T>();
            _getInstanceService = getInstanceService;
            _initializeAction = initializeAction;
        }

        /// <summary>
        /// 获得组件
        /// </summary>
        /// <param name="uniqueId"></param>
        /// <param name="componentType"></param>
        /// <returns></returns>
        public async Task<T> GetComponentAsync(long uniqueId, string componentType)
        {
            return await Task.Run(() =>
            {
                lock (_componentCache)
                {
                    if (_componentCache.TryGetValue(uniqueId, out var instance)) return instance;

                    instance = _getInstanceService.Invoke(componentType);
                    _initializeAction?.Invoke(instance, uniqueId);
                    _componentCache.TryAdd(uniqueId, instance);
                    return instance;
                }

            });
        }

        /// <summary>
        /// 释放所有组件,组件之间有依赖关系的，用同步顺序方式关闭
        /// </summary>
        /// <returns></returns>
        public void ReleaseAll()
        {
            lock (_componentCache)
            {
                foreach (var disposable in _componentCache)
                {
                    disposable.Value.Dispose();
                }
            }
        }

        /// <summary>
        /// 释放指定id组件
        /// </summary>
        /// <param name="uniqueId"></param>
        public void ReleaseOne(long uniqueId)
        {
            lock (_componentCache)
            {
                if (_componentCache.TryGetValue(uniqueId, out var instance))
                {
                    instance.Dispose();
                }
            }
        }

        public int InstanceCount()
        {
            lock (_componentCache)
            {
                return _componentCache.Count;
            }
        }
    }
}
